package com.example.hello.service.impl;

import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import com.example.hello.entity.EmpDO;
import com.example.hello.entity.ExprDO;
import com.example.hello.mapper.EmpMapper;
import com.example.hello.mapper.ExprMapper;
import com.example.hello.model.EmpDetailVO;
import com.example.hello.model.EmpPageRequest;
import com.example.hello.model.PageResult;
import com.example.hello.service.EmpService;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;

@Service
public class EmpServiceImpl implements EmpService {

    private static final Pattern NAME_PATTERN = Pattern.compile("^[\\u4e00-\\u9fa5]{2,10}$");
    private static final Pattern PHONE_PATTERN = Pattern.compile("^\\d{11}$");
    private static final String CACHE_KEY = "emp";

    @Autowired
    private EmpMapper empMapper;

    @Autowired
    private ExprMapper exprMapper;

    @Autowired
    private RedisServiceImpl redisServiceImpl;

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public PageResult<EmpDO> getEmpPage(EmpPageRequest request) {
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        Page<EmpDO> page = (Page<EmpDO>) empMapper.selectByCondition(request);

        PageResult<EmpDO> result = new PageResult<>();
        result.setList(page.getResult());
        result.setTotal(page.getTotal());
        result.setPages(page.getPages());
        result.setPageNum(page.getPageNum());
        result.setPageSize(page.getPageSize());
        // 将员工信息缓存到Redis
        List<EmpDO> emps = page.getResult();
        Map<Integer, EmpDO> empMap = emps.stream()
                .collect(Collectors.toMap(e -> e.getId(), self -> self));
        empMap.entrySet().forEach(entry -> {
            redisServiceImpl.hset(CACHE_KEY, entry.getKey().toString(), entry.getValue());
        });
        return result;
    }

    @Override
    public EmpDetailVO getEmpDetail(Integer id) {
        Object obj = redisServiceImpl.hget(CACHE_KEY, id.toString());
        EmpDO emp = null;
        if (obj != null) {
            // 使用 ObjectMapper 进行类型转换
            emp = objectMapper.convertValue(obj, EmpDO.class);
        } else {
            emp = empMapper.selectById(id);
            if (emp == null) {
                throw new RuntimeException("员工不存在");
            }
            redisServiceImpl.hset(CACHE_KEY, id.toString(), emp);
        }

        EmpDetailVO vo = new EmpDetailVO();
        BeanUtils.copyProperties(emp, vo);
        List<ExprDO> exprList = exprMapper.selectByEmpId(id);
        vo.setExprList(exprList);
        return vo;
    }

    @Override
    @Transactional
    public void createEmp(EmpDO emp) {
        // 参数校验
        validateEmp(emp);

        // 校验用户名和手机号唯一性
        if (empMapper.checkUsernameExists(emp.getUsername()) > 0) {
            throw new RuntimeException("用户名已存在");
        }
        if (empMapper.checkPhoneExists(emp.getPhone()) > 0) {
            throw new RuntimeException("手机号已存在");
        }

        // 设置默认密码
        String defaultPassword = "123456";
        emp.setPassword(DigestUtils.md5DigestAsHex(defaultPassword.getBytes(StandardCharsets.UTF_8)));
        empMapper.insert(emp);
        // 新增后缓存
        redisServiceImpl.hset(CACHE_KEY, emp.getId().toString(), emp);
    }

    @Override
    @Transactional
    public void updateEmp(EmpDO emp) {
        // 参数校验
        validateEmp(emp);

        // 校验员工是否存在
        EmpDO existingEmp = empMapper.selectById(emp.getId());
        if (existingEmp == null) {
            throw new RuntimeException("员工不存在");
        }

        // 校验手机号唯一性
        if (empMapper.checkPhoneExistsForUpdate(emp.getPhone(), emp.getId()) > 0) {
            throw new RuntimeException("手机号已存在");
        }

        empMapper.update(emp);
        // 更新后删除缓存
        redisServiceImpl.hdel(CACHE_KEY, emp.getId().toString());
    }

    @Override
    @Transactional
    public void deleteEmp(Integer id) {
        // 删除员工
        empMapper.deleteById(id);
        // 删除关联的工作经历
        exprMapper.deleteByEmpId(id);
        // 删除后删除缓存
        redisServiceImpl.hdel(CACHE_KEY, id.toString());
    }

    @Override
    @Transactional
    public void deleteEmps(List<Integer> ids) {
        if (ids == null || ids.isEmpty()) {
            throw new RuntimeException("员工ID列表不能为空");
        }
        // 批量删除员工
        empMapper.deleteByIds(ids);
        // 批量删除关联的工作经历
        exprMapper.deleteByEmpIds(ids);
        // 批量删除后删除缓存
        ids.forEach(id -> redisServiceImpl.hdel(CACHE_KEY, id.toString()));
    }

    @Override
    @Transactional
    public void addExpr(Integer empId, ExprDO expr) {
        // 校验员工是否存在
        EmpDO emp = empMapper.selectById(empId);
        if (emp == null) {
            throw new RuntimeException("员工不存在");
        }

        expr.setEmpId(empId);
        exprMapper.insert(expr);
    }

    @Override
    @Transactional
    public void deleteExpr(Integer exprId) {
        exprMapper.deleteById(exprId);
    }

    @Override
    public EmpDO getEmpByUsername(String username) {
        if (username == null || username.isEmpty()) {
            return null;
        }
        return empMapper.selectByUsername(username);
    }

    private void validateEmp(EmpDO emp) {
        // 校验用户名长度
        if (emp.getUsername() == null || emp.getUsername().length() < 2 || emp.getUsername().length() > 20) {
            throw new RuntimeException("用户名长度必须在2-20个字符之间");
        }

        // 校验姓名格式（2-10个汉字）
        if (emp.getName() == null || !NAME_PATTERN.matcher(emp.getName()).matches()) {
            throw new RuntimeException("姓名必须为2-10个汉字");
        }

        // 校验性别
        if (emp.getGender() == null || !("男".equals(emp.getGender()) || "女".equals(emp.getGender()))) {
            throw new RuntimeException("性别必须为'男'或'女'");
        }

        // 校验手机号格式
        if (emp.getPhone() == null || !PHONE_PATTERN.matcher(emp.getPhone()).matches()) {
            throw new RuntimeException("手机号必须为11位数字");
        }
    }
}